<?php

namespace App\Http\Controllers\Api\Train;

use App\Events\Train\TicketQueryEvent;
use App\Events\TripQueryNotifyEvent;
use App\Http\Controllers\Controller;
use App\Http\Requests\Train\TicketQueryRequest;
use App\Http\Resources\Train\StationMapResource;
use App\Http\Resources\Train\TrainListResource;
use App\Http\Resources\Train\Transfer\TrainsToTypeResource;
use App\Http\Resources\Train\Transfer\TransferInfoResource;
use App\Http\Resources\Train\Transfer\TransferListResource;
use App\Models\Train\Stations\Repositories\Interfaces\StationRepositoryInterface;
use App\Models\User\User;
use App\Trip\Orders\TripType;
use App\Trip\Train\Providers\Ctrip\TrainQuery;
use App\Trip\Train\Providers\Ctrip\Transfer;
use App\Trip\Train\TrainQueryFromToData;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Throwable;

class TicketController extends Controller
{

    private StationRepositoryInterface $stationRepo;
    private ?User                      $user;

    public function __construct(StationRepositoryInterface $stationRepository)
    {
        $this->stationRepo = $stationRepository;
        $this->user        = auth()->user() ?: null;
    }


    /**
     * @throws GuzzleException
     * @throws Exception
     * @throws Throwable
     */
    public function query(TicketQueryRequest $request)
    {
        $ret                = [
            "map"           => [],
            "train_numbers" => [],
        ];
        $from               = new TrainQueryFromToData($request->input('from'));
        $to                 = new TrainQueryFromToData($request->input('to'));
        $from_station_codes = $from->parseData2StationCodes();
        $to_station_codes   = $to->parseData2StationCodes();
        $queries            = [];
        foreach ($from_station_codes as $from_station_code) {
            $from_station = $this->stationRepo->findOneByCode($from_station_code);
            foreach ($to_station_codes as $to_station_code) {
                if ($from_station_code == $to_station_code) {
                    continue;
                }
                $query_key           = "{$from_station_code}_{$to_station_code}";
                $to_station          = $this->stationRepo->findOneByCode($to_station_code);
                $param               = [
                    "from_station"      => $from_station->getStationName(),
                    "from_station_code" => $from_station_code,
                    "to_station"        => $to_station->getStationName(),
                    "to_station_code"   => $to_station_code,
                    "train_date"        => $request->input("train_date"),
                ];
                $queries[$query_key] = $param;
            }
        }

        $query                = new TrainQuery();
        $sync                 = count($queries) < 3;
        $ret                  = $query->queryTickets($queries, $sync);
        $trains               = collect($ret['train_numbers'])->unique('train_code');
        $ret['train_numbers'] = TrainListResource::collection($trains);
        $ret['map']           = new StationMapResource($ret['map']);
        event(new TicketQueryEvent([
            'from'       => $from,
            'to'         => $to,
            'ip_address' => $this->getIpAddress(),
            'user'       => $this->user,
            'updated_at' => Carbon::now()->toDateTimeString(),
        ]));
        return $this->success('没有相关的车次哦', $ret);
    }

    /**
     * 中转查询
     *
     * @param Request $request
     *
     * @throws Exception
     * @throws GuzzleException
     */
    public function transfer(Request $request)
    {

        $return = [];

        $from      = new TrainQueryFromToData($request->input('from'));
        $to        = new TrainQueryFromToData($request->input('to'));
        $from_city = $from->parse2City();
        $to_city   = $to->parse2City();
        $param     = [
            "from_name"  => $from_city['name'],
            "from_code"  => $from_city['code'],
            "to_name"    => $to_city['name'],
            "to_code"    => $to_city['code'],
            "train_date" => $request->input("train_date"),
        ];

        $query         = new Transfer();
        $res           = $query->transfer($param);
        $station_codes = collect($res)->map(fn($train) => [
            $train['from_station_code'] => $train['from_station_code'],
            $train['to_station_code']   => $train['to_station_code'],
        ])->collapse();
        $return['map'] = new StationMapResource($station_codes);

        $total                  = collect($res)->count();
        $page                   = $request->input('page', 1) ?: 1;
        $page_size              = $request->input('page_size', 1) ?: 1;
        $last_page              = ceil($total / $page_size);
        $return['trips']        = TransferListResource::collection(collect($res)->forPage($page, $page_size));
        $return['total']        = $total;
        $return['current_page'] = $page;
        $return['last_page']    = $last_page;
        if ($total > 0) {
            event(new TicketQueryEvent([
                'from'       => $from,
                'to'         => $to,
                'user'       => $this->user,
                'updated_at' => Carbon::now()->toDateTimeString(),
            ]));
        }
        return $this->success('没有相关的车次哦', $return);
    }

    /**
     * 中转详情
     *
     * @param Request $request
     *
     * @throws Exception
     * @throws GuzzleException
     */
    public function transfer_detail(Request $request)
    {
        $query                                  = new Transfer();
        $return                                 = [];
        $res                                    = $query->transferInfo([
            'train_date' => $request->input('train_date', Carbon::now()->toDateString()),
        ], $request->input('tripId', '') ?: '');
        $details                                = $res['details'] ?? [];
        $return['transfer']['transfer_minutes'] = $res['transfer_minutes'] ?? 0;
        $return['transfer']['day_difference']   = $res['day_difference'] ?? 0;
        $return['transfer']['type']             = new TrainsToTypeResource($res['trains'] ?? []);
        $return['transfer']['details']          = TransferInfoResource::collection($details);
        $return['transfer']['destination']      = $res['destination'] ?? [];

        $codes         = collect($details)->map(fn($v) => [
            $v['from_station_code'] => $v['from_station_code'],
            $v['to_station_code']   => $v['to_station_code'],
        ])->collapse();
        $return['map'] = new StationMapResource($codes);
        return $this->success('', $return);
    }

    /**
     * 按车次查询结果
     *
     * @param TicketQueryRequest $request
     *
     * @throws GuzzleException
     * @throws Exception
     */
    public function queryByTrain(TicketQueryRequest $request)
    {
        $train_code = $request->input('train_code');
        $train_date = $request->input('train_date');
        if (!$train_code) {
            return $this->error(1, '参数错误');
        }
        $train_info         = [];
        $from               = new TrainQueryFromToData($request->input('from'));
        $to                 = new TrainQueryFromToData($request->input('to'));
        $from_station_codes = $from->parseData2StationCodes();
        $to_station_codes   = $to->parseData2StationCodes();
        foreach ($from_station_codes as $from_station_code) {
            $from_station = $this->stationRepo->findOneByCode($from_station_code);
            foreach ($to_station_codes as $to_station_code) {
                if ($from_station_code == $to_station_code) {
                    continue;
                }
                $to_station = $this->stationRepo->findOneByCode($to_station_code);
                $param      = [
                    "from_station"      => $from_station->getStationName(),
                    "from_station_code" => $from_station_code,
                    "to_station"        => $to_station->getStationName(),
                    "to_station_code"   => $to_station_code,
                    "train_date"        => $train_date,
                ];
                $query      = new \App\Trip\Train\Providers\PiaoChi\TrainQuery();
//                $query      = new  TrainQuery();
                $res = $query->queryTicket($param, true);
                if ($train_info = collect($res["train_numbers"])->firstWhere('train_code', $train_code)) {
                    break;
                }
            }
        }
        if ($train_info) {
            $query = new TrainQuery();
            $query->queryStationPoints($train_code, $train_date);
        }

        return $this->success('', compact('train_info'));
    }

    /**
     * @throws GuzzleException
     * @throws Exception
     */
    public function stocks(TicketQueryRequest $request)
    {
        $train_code = $request->input('train_code');
        if (!$train_code) {
            return $this->error(1, '参数错误');
        }
        Log::info(json_encode(["method" => "刷新库存", "request" => $request->all()], JSON_UNESCAPED_UNICODE));
        $seat_name          = $request->input('seat_name');
        $train_info         = null;
        $from               = new TrainQueryFromToData($request->input('from'));
        $to                 = new TrainQueryFromToData($request->input('to'));
        $from_station_codes = $from->parseData2StationCodes();
        $to_station_codes   = $to->parseData2StationCodes();
        foreach ($from_station_codes as $from_station_code) {
            $from_station = $this->stationRepo->findOneByCode($from_station_code);
            foreach ($to_station_codes as $to_station_code) {
                if ($from_station_code == $to_station_code) {
                    continue;
                }
                $to_station = $this->stationRepo->findOneByCode($to_station_code);
                $param      = [
                    "from_station"      => $from_station->getStationName(),
                    "from_station_code" => $from_station_code,
                    "to_station"        => $to_station->getStationName(),
                    "to_station_code"   => $to_station_code,
                    "train_date"        => $request->input("train_date"),
                ];
                $query      = new \App\Trip\Train\Providers\PiaoChi\TrainQuery();
                $res        = $query->queryTicket($param, true);
                if ($train_info = collect($res["train_numbers"])->firstWhere('train_code', $train_code)) {
                    break;
                }
            }
        }
        $seats = collect($train_info['seats'] ?? [])
            ->map(fn($v) => collect($v)->except(['list', 'select_seats'])->toArray())
            ->when($seat_name, function ($q) use ($seat_name) {
                $q->where('seat_name', $seat_name);
            })
            ->toArray();
        if ($this->user) {
            event(new TripQueryNotifyEvent($this->user, [
                'from'      => $from,
                'to'        => $to,
                'action'    => 'trip_select',
                'trip_type' => TripType::TRIP_TYPE_TRAIN,
            ]));
        }
        return $this->success('', compact('seats'));
    }
}
